package cn.cmft.jc.transform.parse.strategy;

import cn.cmft.jc.transform.parse.ChangeDetail;
import cn.cmft.jc.transform.parse.ChangeOperationType;
import net.sf.jsqlparser.JSQLParserException;
import net.sf.jsqlparser.parser.CCJSqlParserUtil;
import net.sf.jsqlparser.schema.Table;
import net.sf.jsqlparser.statement.Statement;
import net.sf.jsqlparser.statement.alter.Alter;
import net.sf.jsqlparser.statement.alter.AlterExpression;
import net.sf.jsqlparser.statement.alter.AlterOperation;
import net.sf.jsqlparser.statement.alter.RenameTableStatement;
import net.sf.jsqlparser.statement.drop.Drop;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.*;

import static cn.cmft.jc.transform.parse.ChangeOperationType.*;

public class ChangeOptionDDLParseContext {
    private static final Logger logger = LoggerFactory.getLogger(ChangeOptionDDLParseContext.class);
    private static final Map<AlterOperation, ChangeOperationType> operationTypeMap = new HashMap<>();
    static {
        operationTypeMap.put(AlterOperation.ADD,ADD_COLUMN);
        operationTypeMap.put(AlterOperation.DROP,DROP_COLUMN);

        operationTypeMap.put(AlterOperation.CHANGE,CHANGE_COLUMN);
        operationTypeMap.put(AlterOperation.MODIFY,CHANGE_COLUMN);
        operationTypeMap.put(AlterOperation.ALTER,CHANGE_COLUMN);

        operationTypeMap.put(AlterOperation.RENAME,RENAME_COLUMN);
        operationTypeMap.put(AlterOperation.RENAME_TABLE,RENAME_TABLE);
    }
    public AlterExpressionParser createParser(ChangeOperationType operationType){
        switch (operationType){
            case ADD_COLUMN: return new AddColumnParser();
            case DROP_COLUMN: return new DropColumnParser();
            case CHANGE_COLUMN:return new ChangeColumnParser();
            case RENAME_COLUMN:return new RenameColumnParser();
            default:
                throw new IllegalArgumentException("不支持的操作类型: "+operationType);
        }
    }
    public Map<ChangeOperationType, List<ChangeDetail>> executeParse(String ddl){
        Map<ChangeOperationType, List<ChangeDetail>> changeOperationDetails = new HashMap<>();
        try {
            Statement statement = CCJSqlParserUtil.parse(ddl);
            if (statement instanceof Alter){
                changeOperationDetails = alterTypeDDLParse(statement);
            }else if (statement instanceof RenameTableStatement) {
                changeOperationDetails = renameTypeDDLParse(statement);
            }else if (statement instanceof Drop){
                changeOperationDetails = dropTypeDDLParse(statement);
            }else{
                logger.info("不是需要监控的类型，不做处理......");
            }
        } catch (JSQLParserException e) {
            logger.warn("DDL 语句解析错误: ",e);
        }
        return changeOperationDetails;
    }
    private Map<ChangeOperationType, List<ChangeDetail>> dropTypeDDLParse(Statement statement) {
        Map<ChangeOperationType, List<ChangeDetail>> changeOperationDetails = new HashMap<>();
        Drop drop = (Drop) statement;
        if (drop.getType().equals("TABLE")){
            changeOperationDetails.put(ChangeOperationType.DROP_TABLE,new ArrayList<>());
        }
        return changeOperationDetails;
    }
    private Map<ChangeOperationType, List<ChangeDetail>> renameTypeDDLParse(Statement statement) {
        Map<ChangeOperationType, List<ChangeDetail>> changeOperationDetails = new HashMap<>();
        RenameTableStatement rename = (RenameTableStatement) statement;
        Set<Map.Entry<Table, Table>> tableNames = rename.getTableNames();
        ArrayList<ChangeDetail> changeDetails = new ArrayList<>();
        for (Map.Entry<Table,Table> tableEntry: tableNames){
            ChangeDetail changeDetail = new ChangeDetail();
            changeDetail.setOldTableName( tableEntry.getKey().toString());
            changeDetail.setCurrentTableName(tableEntry.getValue().toString());
            changeDetails.add(changeDetail);
        }
        changeOperationDetails.put(ChangeOperationType.RENAME_TABLE, changeDetails);
        return changeOperationDetails;
    }
    private Map<ChangeOperationType, List<ChangeDetail>> alterTypeDDLParse(Statement statement){
        HashMap<ChangeOperationType, List<ChangeDetail>> changeOperationDetails = new HashMap<>();
        Alter alter = (Alter) statement;
        List<AlterExpression> alterExpressions = alter.getAlterExpressions();
        for (AlterExpression alterExpression: alterExpressions){
            // 获取操作类型
            AlterOperation operation = alterExpression.getOperation();
            // 如果ChangeOperationType 不包含 会报错
            try{
                ChangeOperationType operationType = operationTypeMap.get(operation);
                //不支持的操作类型不处理： eg DROP_PRIMARY_KEY
                if (Objects.isNull(operationType)){continue;}
                //ChangeOperationType operationType = ChangeOperationType.valueOf(operation.name());
                // 根据操作类型初始化parser
                AlterExpressionParser parser = createParser(operationType);
                // parser 解析后获取的列数据
                List<ChangeDetail> columns = parser.parse(alterExpression);
                if (columns.isEmpty()){
                    continue;
                }

                if (changeOperationDetails.containsKey(operationType)){
                    changeOperationDetails.get(operationType).addAll(columns);
                }else{
                    changeOperationDetails.put(operationType,columns);
                }
            } catch (IllegalArgumentException e) {
                logger.warn("不支持的操作类型：",e);
            }
        }
        return changeOperationDetails;
    }
}
